﻿using System;
using System.Collections.Generic;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.Text;

using Microsoft.ResourceManagement.Client.WsTransfer;

namespace Microsoft.ResourceManagement.Client.WsTransfer
{
    public class WsTransferFactoryClient : System.ServiceModel.ClientBase<IResourceFactory>, IResourceFactory
    {
        public WsTransferFactoryClient()
            : base()
        {
        }

        public WsTransferFactoryClient(string endpointConfigurationName) :
            base(endpointConfigurationName)
        {
        }

        public WsTransferFactoryClient(string endpointConfigurationName, string remoteAddress) :
            base(endpointConfigurationName, remoteAddress)
        {
        }

        public WsTransferFactoryClient(string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress) :
            base(endpointConfigurationName, remoteAddress)
        {
        }

        public WsTransferFactoryClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) :
            base(binding, remoteAddress)
        {
        }

        public Message Create(Message request)
        {
            IResourceFactory channel = base.ChannelFactory.CreateChannel();
            try
            {
                Message ret = channel.Create(request);
                ((IDisposable)channel).Dispose();
                return ret;
            }
            catch (Exception)
            {
                if (((ICommunicationObject)channel).State == CommunicationState.Faulted)
                {
                    ((ICommunicationObject)channel).Abort();
                }
                throw;
            }
        }

        public CreateResponse Create(CreateRequest request)
        {
            if (request == null)
            {
                throw new ArgumentNullException("request");
            }
            if (request.AddRequest == null)
            {
                throw new ArgumentNullException("AddRequest");
            }
            Message createRequest = null;
            lock (request)
            {
                createRequest = Message.CreateMessage(MessageVersion.Default, Constants.WsTransfer.CreateAction, request.AddRequest, new ClientSerializer(typeof(AddRequest)));
                ClientHelper.AddImdaHeaders(request as ImdaRequest, createRequest);
            }
            Message createResponse = Create(createRequest);

            if (createResponse.IsFault)
            {
                ClientHelper.HandleFault(createResponse);
            }

            CreateResponse createResponseTyped = new CreateResponse();
            // for a reason which is not clear, this isn't working
            // createResponseTyped.ResourceCreated = createResponse.GetBody<ResourceCreated>(new ClientSerializer(typeof(ResourceCreated)));

            // alternative way to de-serialize the message...
            System.Xml.XmlNode body = createResponse.GetBody<System.Xml.XmlNode>(new ClientSerializer(typeof(System.Xml.XmlNode)));
            createResponseTyped.ResourceCreated = new ResourceCreated();
            createResponseTyped.ResourceCreated.EndpointReference = new EndpointReference();
            try
            {
                createResponseTyped.ResourceCreated.EndpointReference.Address = body["EndpointReference"]["Address"].InnerText;
                createResponseTyped.ResourceCreated.EndpointReference.ReferenceProperties = new ReferenceProperties();
                createResponseTyped.ResourceCreated.EndpointReference.ReferenceProperties.ResourceReferenceProperty = new ResourceReferenceProperty();
                createResponseTyped.ResourceCreated.EndpointReference.ReferenceProperties.ResourceReferenceProperty.Value = body["EndpointReference"]["ReferenceProperties"]["ResourceReferenceProperty"].InnerText;
            }
            catch (NullReferenceException)
            {
            }
            return createResponseTyped;
        }
    }
}
